﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Transactions;
using T.FAS.Runtime.Base.Dao;
using T.FAS.Runtime.Metadata.Entity.ScheduleJob;
using T.ServiceComponent.DAC.Service;
using T.ServiceComponent.DataAccessEx.Core;

namespace T.FAS.Runtime.ScheduleJob.Dao
{
    public class ScheduleJobELBDao : DaoService<Metadata.Entity.ScheduleJob.ScheduleJob>, IScheduleJobDao
    {
        public const string MetaDataID = "ScheduleJob";
        public const string MetaDataName = "ScheduleJob元数据";
        public override string TableName => "FAS_ScheduleJob";
        public override string IDColumnName => "ID";
        public override List<string> ExceptColumnName
            => DaoUtil.GetExceptionColumn<Metadata.Entity.ScheduleJob.ScheduleJob>(
                new List<string>
                {
                    "MetaDataID",
                    "MetaDataCode",
                    "MetaDataName",
                    "ProjectBranchID",
                }
            );

        public override Dictionary<string, PropertyInfo> GetColumns()
        {
            return DaoServiceExtension.GetAllColumns<Metadata.Entity.ScheduleJob.ScheduleJob>(base.GetColumns());
        }

        public override Dictionary<string, object> GetDataMapping(Metadata.Entity.ScheduleJob.ScheduleJob data)
        {
            var mapping = base.GetDataMapping(data);
            mapping.Remove("JobType");
            mapping.Add("JobType", (int)data.JobType);

            mapping.Remove("FailureStrategy");
            mapping.Add("FailureStrategy", (int)data.FailureStrategy);

            return mapping;
        }

        public override Metadata.Entity.ScheduleJob.ScheduleJob ConvertToObject(Dictionary<string, PropertyInfo> columns, DataRow row)
        {
            if (columns.ContainsKey("JobType"))
                columns.Remove("JobType");
            if (columns.ContainsKey("IsPersistent"))
                columns.Remove("IsPersistent");
            if (columns.ContainsKey("IsAutoRecovery"))
                columns.Remove("IsAutoRecovery");
            if (columns.ContainsKey("IsAllowConcurrentExecution"))
                columns.Remove("IsAllowConcurrentExecution");
            if (columns.ContainsKey("IsDisabled"))
                columns.Remove("IsDisabled");
            if (columns.ContainsKey("IsSysDefault"))
                columns.Remove("IsSysDefault");
            if (columns.ContainsKey("EnableLog"))
                columns.Remove("EnableLog");
            if (columns.ContainsKey("EnableMonitor"))
                columns.Remove("EnableMonitor");
            if (columns.ContainsKey("FailureStrategy"))
                columns.Remove("FailureStrategy");


            var data = base.ConvertToObject(columns, row);

            data.JobType = (JobType)Enum.Parse(typeof(JobType), Convert.ToString(row["JobType"]));
            data.IsPersistent = DaoUtil.IntConvertBool(row["IsPersistent"]);
            data.IsAutoRecovery = DaoUtil.IntConvertBool(row["IsAutoRecovery"]);
            data.IsAllowConcurrentExecution = DaoUtil.IntConvertBool(row["IsAllowConcurrentExecution"]);
            data.IsDisabled = DaoUtil.IntConvertBool(row["IsDisabled"]);
            data.IsSysDefault = DaoUtil.IntConvertBool(row["IsSysDefault"]);
            data.EnableLog = DaoUtil.IntConvertBool(row["EnableLog"]);
            data.EnableMonitor = DaoUtil.IntConvertBool(row["EnableMonitor"]);
            data.FailureStrategy = (FailureStrategy)Enum.Parse(typeof(FailureStrategy), Convert.ToString(row["FailureStrategy"]));

            return data;
        }
        private ScheduleJobDataELBDao scheduleJobDataELBDao => new ScheduleJobDataELBDao();
        private ScheduleTriggerELBDao scheduleTriggerELBDao => new ScheduleTriggerELBDao();
        public void AddScheduleJob(Metadata.Entity.ScheduleJob.ScheduleJob sJob)
        {
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
                {
                    if (sJob != null)
                    {
                        ScheduleJobInitBeforeSave(sJob);
                    }
                    base.Add(new List<object> { sJob });
                    if (sJob.ScheduleJobDatas != null)
                    {
                        sJob.ScheduleJobDatas.ForEach(x => x.ScheduleJobID = sJob.ID);
                        scheduleJobDataELBDao.Add(sJob.ScheduleJobDatas);
                    }
                    if (sJob.ScheduleTrigger != null)
                    {
                        scheduleTriggerELBDao.AddScheduleTrigger(sJob, sJob.ScheduleTrigger);
                    }

                    scope.Complete();
                }
            }
            catch (Exception e)
            {

                throw new Exception($"{MetaDataName}:{sJob.Code}保存失败！", e);
            }
        }
        private void ScheduleJobInitBeforeSave(Metadata.Entity.ScheduleJob.ScheduleJob sJob)
        {
            if(sJob == null)
                return;
            sJob.CreateTime = InitDataTime(sJob.CreateTime, DateTime.Now);
            sJob.LastModifyTime = InitDataTime(sJob.LastModifyTime, DateTime.Now);
            sJob.IsPersistent = true;
            sJob.IsAutoRecovery = true;
            if (string.IsNullOrEmpty(sJob.ScheduleGroup))
            {
                sJob.ScheduleGroup = sJob.Code + "Group";
            }
            if (string.IsNullOrEmpty(sJob.BusinessType))
            {
                sJob.BusinessType = sJob.Code;
            }
            if (string.IsNullOrEmpty(sJob.Description))
            {
                sJob.Description = sJob.Code;
            }
            if (sJob.ScheduleTrigger != null)
            {
                sJob.ScheduleTrigger.CreateTime = InitDataTime(sJob.ScheduleTrigger.CreateTime, DateTime.Now);
                sJob.ScheduleTrigger.LastModifyTime = InitDataTime(sJob.ScheduleTrigger.LastModifyTime, DateTime.Now);
                sJob.ScheduleTrigger.ExpiredTime = InitDataTime(sJob.ScheduleTrigger.ExpiredTime, Convert.ToDateTime(ScheduleJobConst.SysDefaultExpiredTime));
                if (string.IsNullOrEmpty(sJob.ScheduleTrigger.Code))
                {
                    sJob.ScheduleTrigger.Code = sJob.Code+"Trigger";
                }
                if (string.IsNullOrEmpty(sJob.ScheduleTrigger.Name))
                {
                    sJob.ScheduleTrigger.Name = sJob.Name + "Trigger";
                }
                if (string.IsNullOrEmpty(sJob.ScheduleTrigger.Description))
                {
                    sJob.ScheduleTrigger.Description = sJob.Description + "Trigger";
                }
                if (string.IsNullOrEmpty(sJob.ScheduleTrigger.TriggerGroup))
                {
                    sJob.ScheduleTrigger.TriggerGroup = sJob.ScheduleTrigger.Code + "Group";
                }
            }
            if (sJob.ScheduleJobDatas != null)
            {
                sJob.ScheduleJobDatas.ForEach(data =>
                {
                    data.CreateTime = InitDataTime(data.CreateTime, DateTime.Now);
                    data.LastModifyTime = InitDataTime(data.LastModifyTime, DateTime.Now);
                });
            }
        }

        public int CheckUnique(Dictionary<string, string> filter)
        {
            List<IDbDataParameter> paramsList = new List<IDbDataParameter>();
            var sql = "select count(1) from {0} where 1=1 ";
            if (filter.ContainsKey("Code"))
            {
                sql += " and Code = @Code";
                paramsList.Add(DB.MakeInParam("@Code", TDbDataType.VarChar, filter["Code"]));
            }
            if (filter.ContainsKey("TenantID"))
            {
                sql += " and TenantID = @TenantID";
                paramsList.Add(DB.MakeInParam("@TenantID", TDbDataType.VarChar, filter["TenantID"]));
            }
            if (filter.ContainsKey("ID"))
            {
                sql += " and ID <> @ID";
                paramsList.Add(DB.MakeInParam("@ID", TDbDataType.VarChar, filter["ID"]));
            }
            var count = DB.ExecSqlStatement(string.Format(sql, this.TableName), paramsList);
            return count == null ? 0 : count;
        }

        public void DeleteScheduleJob(string sJobID)
        {
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
                {
                    //删除关联的Trigger
                    scheduleTriggerELBDao.DeleteScheduleTriggerByScheduleJobID(sJobID);
                    //删除ScheduleJobData
                    scheduleJobDataELBDao.DeleteScheduleJobDataByJobID(sJobID);
                    //删除ScheduleJob
                    base.Delete(new List<string> { sJobID });
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new Exception($"{MetaDataName}:删除失败！", e);
            }
        }

        public List<Metadata.Entity.ScheduleJob.ScheduleJob> GetScheduleJobByFilter(Dictionary<string, string> filter)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 根据任务ID获取任务数据
        /// </summary>
        /// <param name="sJobID"></param>
        /// <returns></returns>
        public Metadata.Entity.ScheduleJob.ScheduleJob GetScheduleJobByID(string sJobID)
        {
            var jobMetaData = base.Get(sJobID);
            var sJob = jobMetaData as Metadata.Entity.ScheduleJob.ScheduleJob;
            if (sJob == null)
                return null;
            sJob.ScheduleJobDatas = scheduleJobDataELBDao.GetScheduleJobDataByJobID(sJobID);
            sJob.ScheduleTrigger = scheduleTriggerELBDao.GetScheduleTriggerByScheduleJobID(sJobID);
            return sJob;
        }

        public void UpdateScheduleJob(Metadata.Entity.ScheduleJob.ScheduleJob sJob)
        {
            throw new NotImplementedException();
        }

        private DateTime InitDataTime(DateTime curDateTime, DateTime defaultTime)
        {
            if (curDateTime == null || curDateTime.Year < 2000)
            {
                curDateTime = defaultTime;
            }
            return curDateTime;
        }
        
    }
}

